namespace SimpleWebServices.Web
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Text;
    using System.Web;
    using SimpleWebServices.Data;

    public static class HttpRequestBaseExtensionMethods
    {
        public static string RawQueryString(this HttpRequestBase request)
        {
            if (null == request)
            {
                throw new ArgumentNullException("request");
            }

            int index = request.RawUrl.IndexOf('?');

            return (-1 == index) ? string.Empty : request.RawUrl.Substring(index);
        }

        public static string RawQueryString(this HttpRequestBase request, Token? token)
        {
            return request.RawQueryString(token, null);
        }

        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Guid", Justification = "This is necessary because Guid doesn't have a TryParse method.")]
        public static string RawQueryString(this HttpRequestBase request, Token? token, string whence)
        {
            if (!string.IsNullOrEmpty(whence))
            {
                whence = HttpUtility.UrlEncode(whence);
            }

            StringBuilder buffer = new StringBuilder();
            buffer.Append(token);
            string[] parts = RawQueryStringParts(request);
            if (0 != parts.Length)
            {
                if (36 == parts[0].Length)
                {
                    try
                    {
                        Guid guid = new Guid(parts[0]);
                    }
                    catch (FormatException)
                    {
                        buffer.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", 0 == buffer.Length ? string.Empty : "&", parts[0]);
                    }
                }
                else
                {
                    buffer.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", 0 == buffer.Length ? string.Empty : "&", parts[0]);
                }

                for (int i = 1; i < parts.Length; i++)
                {
                    if (!parts[i].StartsWith("whence=", StringComparison.OrdinalIgnoreCase))
                    {
                        buffer.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}", 0 == buffer.Length ? string.Empty : "&", parts[i]);
                    }
                }
            }

            if (!string.IsNullOrEmpty(whence))
            {
                buffer.AppendFormat(CultureInfo.InvariantCulture, "{0}whence={1}", 0 == buffer.Length ? string.Empty : "&", whence);
            }

            return (0 == buffer.Length ? string.Empty : "?") + buffer.ToString();
        }

        public static T Tokenized<T>(this HttpRequestBase request)
            where T : IRecord
        {
            T value = default(T);

            Token? token = request.Token();
            if (token.HasValue)
            {
                try
                {
                    value = Record.Retrieve<T>(token.Value);
                }
                catch (InvalidOperationException)
                {
                }
            }

            return value;
        }

        public static Token? Token(this HttpRequestBase request)
        {
            Token? result = null;

            string[] parts = RawQueryStringParts(request);
            if (0 != parts.Length && 36 == parts[0].Length)
            {
                try
                {
                    result = new Guid(parts[0]);
                }
                catch (FormatException)
                {
                }
            }

            return result;
        }

        private static string[] RawQueryStringParts(HttpRequestBase request)
        {
            string query = request.RawQueryString();
            query = query.StartsWith("?", StringComparison.OrdinalIgnoreCase) ? query.Substring(1) : query;
            return query.Split(new char[] { '&' }, StringSplitOptions.RemoveEmptyEntries);
        }
    }
}